import struct
from functools import reduce
from func.utils import *


class Frame_33:
    def __init__(self):
        """初始化帧构建器"""
        self._seq_num = 0  # 内部序列号计数器
        self.st = 0x33     # 固定厂商控制字
        
    def build_frame(self, cmd_type, data, is_first_packet=True, packet_seq=0):
        """构建完整的数据帧
        Args:
            cmd_type: 命令类型(如0xAC)
            data: 要发送的数据列表(可为None或空列表)
            is_first_packet: 是否为第一个分包
            packet_seq: 分包序列号(N-1到0)
        Returns:
            完整的帧数据列表 [ST, SN, CTL, LEN, TYPE, SN, LEN, CMD, LEN, DATA..., BCC]
        """
         
        # 更新并获取序列号(0x00-0x0F循环)
        self._seq_num = (self._seq_num + 1) & 0x0F
        sn = self._seq_num
        
        # 构建控制字
        ctl = self._build_ctl_byte(is_first_packet, packet_seq)

        # 处理空数据情况
        if data is None:
            data = cmd_type
            frame = [self.st, sn, ctl, len(data)]
            frame.extend(data)
        else:
            # 构建完整帧
            frame = [self.st, sn, ctl, len(data)+6]  # 总长度包括TYPE,SN,LEN,CMD,LEN
            # 处理cmd_type为int类型的情况
            if isinstance(cmd_type, int):
                frame.extend(cmd_type.to_bytes(1, byteorder='little'))
            else:
                frame.extend(cmd_type)
            frame.extend([0x00])
            frame.extend(struct.pack('<H', len(data)+2))
            frame.extend([0x80, len(data)])
            frame.extend(data)

        # 添加BCC校验
        frame.append(self._calculate_bcc(frame[1:]))
        return frame
    
    def _build_ctl_byte(self, is_first_packet, packet_seq):
        """构建CTL控制字节
        Args:
            is_first_packet: 是否为首包
            packet_seq: 分包序列号
        Returns:
            控制字节
        """
        return (0x80 if is_first_packet else 0x00) | (packet_seq & 0x7F)
    
    def _calculate_bcc(self, data):
        """计算BCC校验码(XOR从SN开始到DATA结束)
        Args:
            data: 要校验的数据部分
        Returns:
            单字节校验码
        """
        return reduce(lambda x, y: x ^ y, data, 0) & 0xFF

class ZEEKR_Issuer:
    def __init__(self):
        self.frame_builder = Frame_33()  # 使用Frame_33类构建帧
        self.MAC = None  # 初始化MAC值
           
    def handshake(self):
        """1. 握手流程"""
        cmd_type = [0xA2]  # 握手命令类型
        data = None  # 握手不需要数据部分
        handshake_frame = self.frame_builder.build_frame(cmd_type, data)
        return handshake_frame

    def select_directory(self, cmd_type, dir_id, data = [0x01, 0x07, 0x00, 0xA4, 0x00, 0x00, 0x02]):
        """2. 切换目录
        Args:
            cmd_type: 命令类型
            dir_id: 目录ID列表 [0x3F, 0x00]
        """
        # data = [cmd_type] + [0x00] + [0x0B, 0x00] + [0x80] + [0x09] + data + dir_id
        data = data + dir_id
        return self.frame_builder.build_frame(cmd_type, data)

    def get_random(self, cmd_type):
        """3. 获取随机数"""
        data = [0x01, 0x05, 0x00, 0x84, 0x00, 0x00, 0x04]
        return self.frame_builder.build_frame(cmd_type, data)

    def read_system_info(self):
        """4. 读取系统信息"""
        cmd_type = 0xAC 
        data = [0x01, 0x05, 0x00, 0xB0, 0x81, 0x00, 0x63]
        return self.frame_builder.build_frame(cmd_type, data)

    def read_system_info_2(self):
        """4. 读取系统信息"""
        cmd_type = 0xAC 
        data = [0x01, 0x05, 0x00, 0xB0, 0x81, 0x0A, 0x08]
        return self.frame_builder.build_frame(cmd_type, data)

    def read_Tampers_info(self):
        """4. 读取防拆位信息"""
        cmd_type = 0xAC 
        data = [0x01, 0x05, 0x00, 0xB0, 0x81, 0x1A, 0x01]
        return self.frame_builder.build_frame(cmd_type, data)
    
    def write_Tampers_status(self, tamper_status=1, iv=[]):
        """
        写入防拆位状态
        Args:
            tamper_status: 防拆状态值(1字节)
            iv: 初始向量(字节类型)
        Returns:
            构建的帧数据
        """
        cmd_type = 0xAC
        iv_str = ''.join(format(byte, '02X') for byte in iv)
        # 确保iv长度为32字节
        if len(iv_str) < 32:
            iv_str = iv_str + '0' * (32 - len(iv_str))
        logging.info(f"IV: {iv_str}")
        # 计算MAC
        tamper_status_str = f'{tamper_status:02X}'
        mac_hex = self.calculate_sm4_mac(data="04D6811A05" + tamper_status_str, iv=iv_str)
        logging.info(f"MAC: {mac_hex}")
        # 转换为字节数组
        MAC =self.strToToHexBytes(mac_hex)
        # 构建数据部分
        data = [0x04, 0xD6, 0x81, 0x1A, 0x05] + [tamper_status] + MAC
        return self.frame_builder.build_frame(cmd_type, data)

    '''转换字符串为数组'''
    def strToToHexBytes(self,hexString):
        '''
        字符串转换为16进制数组
        :param hexString: 16进制字符串
        :return: 16进制数组
        '''
        hexString = str(hexString).replace(' ', '').replace('[', '').replace(']', '').replace('\'', '')

        if ((len(hexString) % 2) != 0):
            hexString += " "

        c_16_temp = list(hexString)
        ilen = int(len(c_16_temp) / 2)
        hexBytes = [0] * ilen
        for index in range(ilen):
            hexBytes[index] = int((c_16_temp[2 * index] + c_16_temp[2 * index + 1]),16)
        return hexBytes

    def calculate_sm4_mac(self, key='0' * 32, data="", iv='0' * 32):
        """
        计算SM4 MAC
        :param key: 密钥
        :param data: 数据
        :param iv: 初始向量
        :return: MAC值
        """
        iv= iv.replace(' ', '')
        if len(iv) < 32:
            iv = iv + '0' * (32 - len(iv))
        out = sm4_mac(key, data, iv)
        return out

    def read_card_id(self):
        """4. 读取CARD ID"""
        cmd_type = 0xAC 
        data = [0x01, 0x05, 0x00, 0xB0, 0x96, 0x00, 0x06]
        return self.frame_builder.build_frame(cmd_type, data)

    def read_file_15(self):
        """5. 读取0015文件"""
        cmd_type = [0xA3]
        data = [0x01, 0x05, 0x00, 0xB0, 0x95, 0x00, 0x32]
        return self.frame_builder.build_frame(cmd_type, data)

    def read_file_EF01(self):
        """5. 读取0015文件"""
        cmd_type = [0xB0]
        data = [0x81, 0x1A, 0x01]
        return self.frame_builder.build_frame(cmd_type, data)

    def disconnect(self):
        """7. 断开连接"""
        cmd_type = [0xAE]
        data = [0x01, 0xC3]
        return self.frame_builder.build_frame(cmd_type, data)

    def issue_etc(self):
        """执行完整的ETC发行流程"""
        steps = [
            ("握手", lambda: self.handshake()),
            ("切换3F00目录(CPU卡)", lambda: self.select_directory(0xA3, [0x3F, 0x00])),
            ("获取随机数(OBU)", lambda: self.get_random(0xAC)),
            ("断开连接", lambda: self.disconnect())
        ]
        
        try:
            for step_name, step_func in steps:
                step_func()
            return True, "ETC发行流程执行成功"
        except Exception as e:
            return False, f"发行失败: {str(e)}"

# 示例用法
if __name__ == "__main__":
    
    # 初始化读卡器
    reader = readers()[0]
    connection = reader.createConnection()
    connection.connect()

    # 创建发行器实例
    issuer = ZEEKR_Issuer(connection)

    # 执行发行流程
    success, message = issuer.issue_etc()
    print(f"发行结果: {success}, 消息: {message}")